﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RQX.Common.Core.Hardware.Net
{
    public class TcpSocketServer
    {
        public ConcurrentDictionary<EndPoint, TcpSocketConnection> _socketList { get; } = new ConcurrentDictionary<EndPoint, TcpSocketConnection>();
        
        #region 内部字段
        private readonly string _ip;
        private readonly int _port;
        private readonly IPEndPoint _iep;
        private readonly Socket _socket;
        private bool _isAlive = true;
        /// <summary>
        /// 最大挂起连接数
        /// </summary>
        private const int MAX_QUEUE = int.MaxValue;
        #endregion

        #region 构造函数
        public TcpSocketServer(TcpSocketServer source) : this(source._ip, source._port)
        {
            HandleClosed = source.HandleClosed;
            HandleException = source.HandleException;
            HandleMsgReceived = source.HandleMsgReceived;
            HandleMsgSended = source.HandleMsgSended;
            HandleServerAccepted = source.HandleServerAccepted;
            HandleServerException = source.HandleServerException;
            HandleServerStarted = source.HandleServerStarted;
            HandleServerStoped = source.HandleServerStoped;
            HandleServerStopping = source.HandleServerStopping;
        }
        public TcpSocketServer(int port) : this("127.0.0.1", port) { }
        public TcpSocketServer(string ip, int port)
        {
            _ip = ip;
            _port = port;
            _iep = new IPEndPoint(IPAddress.Parse(_ip), _port);
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        #endregion

        #region 对外接口
        /// <summary>
        /// 启动开始监听
        /// </summary>
        public void Start()
        {
            TryCatchMethod(() =>
            {
                _socket.Bind(_iep);
                _socket.Listen(MAX_QUEUE);
                HandleServerStarted?.Invoke(this);
            });
            SocketStatusCheckThread();
            StartAccept();
        }
        /// <summary>
        /// 服务端退出
        /// </summary>
        public void Close()
        {
            _isAlive = false;
            HandleServerStopping?.Invoke(this);
            foreach (var key in _socketList.Keys)
            {
                _socketList.TryRemove(key, out var conn);
                conn.Close();
            }
            _socket.Close();
            HandleServerStoped?.Invoke(this);
        }

        public string ShowInfo() => $"{_ip}:{_port}";
        #endregion

        #region 内部函数
        /// <summary>
        /// Socket连接状态监测线程
        /// </summary>
        private void SocketStatusCheckThread()
        {
            Thread checkThread = new Thread(() =>
            {
                while (true)
                {
                    foreach (var key in _socketList.Keys)
                    {
                        _socketList.TryGetValue(key, out var conn);
                        conn.CheckIsConnected();
                    }
                    Thread.Sleep(1000);
                }
            })
            {
                IsBackground = true
            };
            checkThread.Start();
        }

        private void StartAccept()
        {
            TryCatchMethod(() =>
            {
                _socket.BeginAccept(asyncAccept =>
                {
                    TryCatchMethod(() =>
                    {
                        var newSocket = _socket.EndAccept(asyncAccept);
                        if (_isAlive)
                        {
                            var socketConn = new TcpSocketConnection(this, newSocket)
                            {
                                HandleMsgSended = HandleMsgSended,
                                HandleClosed = HandleClosed,
                                HandleException = HandleException,
                                HandleMsgReceived = HandleMsgReceived,
                            };
                            _socketList.TryAdd(newSocket.RemoteEndPoint, socketConn);
                            HandleServerAccepted?.Invoke(socketConn);
                        }
                        else
                        {
                            newSocket.Close();
                        }
                    });
                    StartAccept();
                }, null);
            });
        }

        private void TryCatchMethod(Action action)
        {
            try
            {
                action();
            }
            catch (Exception ex)
            {
                Close();
                HandleServerException?.Invoke(this, ex);
            }
        }
        #endregion

        #region 事件处理
        /// <summary>
        /// 服务端启动后事件
        /// </summary>
        /// <returns></returns>
        public Action<TcpSocketServer> HandleServerStarted { get; set; }
        /// <summary>
        /// 服务端停止后事件
        /// </summary>
        public Action<TcpSocketServer> HandleServerStoped { get; set; }
        /// <summary>
        /// 服务端停止前事件
        /// </summary>
        public Action<TcpSocketServer> HandleServerStopping { get; set; }
        /// <summary>
        /// 服务端接收到新连接后事件
        /// </summary>
        public Action<TcpSocketConnection> HandleServerAccepted { get; set; }
        /// <summary>
        /// 接收到数据触发的事件
        /// </summary>
        public Action<TcpSocketConnection, byte[]> HandleMsgReceived { get; set; }
        /// <summary>
        /// 发送数据后触发的事件
        /// </summary>
        public Action<TcpSocketConnection, byte[]> HandleMsgSended { get; set; }
        /// <summary>
        /// 连接关闭事件
        /// </summary>
        public Action<TcpSocketConnection> HandleClosed { get; set; }
        /// <summary>
        /// 异常处理事件
        /// </summary>
        public Action<TcpSocketConnection, Exception> HandleException { get; set; }
        /// <summary>
        /// 总服务异常处理事件
        /// </summary>
        public Action<TcpSocketServer, Exception> HandleServerException { get; set; }
        #endregion
    }
}
